package cn.net.vote.util;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;

import com.alibaba.druid.util.StringUtils;
import com.google.gson.JsonObject;
import io.searchbox.client.JestResultHandler;
import io.searchbox.cluster.UpdateSettings;
import io.searchbox.core.*;
import io.searchbox.indices.ClearCache;
import io.searchbox.indices.Optimize;
import io.searchbox.indices.aliases.AddAliasMapping;
import io.searchbox.indices.aliases.GetAliases;
import io.searchbox.indices.aliases.ModifyAliases;
import io.searchbox.indices.settings.GetSettings;
import io.searchbox.indices.template.GetTemplate;
import io.searchbox.indices.template.PutTemplate;
import org.apache.commons.codec.digest.DigestUtils;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestClientFactory;
import io.searchbox.client.JestResult;
import io.searchbox.client.config.HttpClientConfig;
import io.searchbox.indices.CreateIndex;
import io.searchbox.indices.DeleteIndex;
import io.searchbox.indices.mapping.GetMapping;
import io.searchbox.indices.mapping.PutMapping;
import org.elasticsearch.search.highlight.HighlightBuilder;

import javax.xml.ws.Response;

import static io.searchbox.cluster.UpdateSettings.*;

public class JestUtil {
		private static JestClient jestClient = getJestClient();
		private static final String PWDKEY = "X-SCE-ES-PASSWORD";

		public static  JestClient getJestClient() {
	    	JestClientFactory factory = new JestClientFactory();
			String esip = ConfigUtil.getString("custom.elasticsearch.elasticIps");
			factory.setHttpClientConfig(new HttpClientConfig.Builder(esip).connTimeout(600000).readTimeout(600000).multiThreaded(true).build());
	        return factory.getObject();  
	    }

	    
	    
	    /**
	     * 全文搜索
	     */
	    public static String serachAll(JestClient jestClient,String query,String indexName,String typeName) {
			String result = "";
			try {
				SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //构造搜索对象
				searchSourceBuilder.query(QueryBuilders.queryStringQuery(query)); //设置查询条件
		    	//分页设置
		    	searchSourceBuilder.from(0).size(1000);
		        System.out.println("全文搜索查询语句:"+searchSourceBuilder.toString());
				System.out.println("全文搜索返回结果:"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));
				result= search(jestClient,indexName, typeName, searchSourceBuilder.toString()).toString();

			} catch (Exception e) {
				e.printStackTrace();
			}
			return result;
		}
	    
	    /**
	     * 精确搜索
	     */
	    public static String serachSingle(JestClient jestClient,String name, String value ,String indexName,String typeName) {
			String result = "";
			try {
				SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 
		    	searchSourceBuilder.query(QueryBuilders.termQuery(name, value));
				result = search(jestClient,indexName, typeName, searchSourceBuilder.toString());
		    	System.out.println("精确搜索查询语句:"+searchSourceBuilder.toString());
				System.out.println("精确搜索返回结果:"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));
			} catch (Exception e) {
				e.printStackTrace();
			}
			return result;
		}
	    
	    
	    /**
	     * 区间搜索
	     */
	    public static void serachBetween(String start,String end,String indexName,String typeName) {
			String createtm="createtm";
			try {
				SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 
		    	searchSourceBuilder.query(QueryBuilders.rangeQuery(createtm).gte(start).lte(end));
		    	System.out.println("区间搜索语句:"+searchSourceBuilder.toString());
				System.out.println("区间搜索返回结果:"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}


	    /**
	     * 创建索引
	     * @param indexName
	     * @return
	     * @throws Exception
	     */
	    public boolean createIndex(JestClient jestClient,String indexName) throws Exception {  
	        JestResult jr = jestClient.execute(new CreateIndex.Builder(indexName).build());  
	        return jr.isSucceeded();  
	    }  
	      
	    /**
	     * 新增数据
	     * @param indexName
	     * @param typeName
	     * @param source
	     * @return
	     * @throws Exception
	     */
	    public boolean insert(JestClient jestClient,String indexName, String typeName, String source) throws Exception {  
	        PutMapping putMapping = new PutMapping.Builder(indexName, typeName, source).build();  
	        JestResult jr = jestClient.execute(putMapping);
	        return jr.isSucceeded();  
	    }  
	      
	    
	     /**
	      * 查询数据
	      * @param indexName
	      * @param typeName
	      * @return
	      * @throws Exception
	      */
	    public static String getIndexMapping(JestClient jestClient,String indexName, String typeName) throws Exception {  
	        GetMapping getMapping = new GetMapping.Builder().addIndex(indexName).addType(typeName).build();  
	        JestResult jr =jestClient.execute(getMapping);  
	        return jr.getJsonString();  
	     }  
	      
	    
	    
	   /**
	    * 批量新增数据
	    * @param indexName
	    * @param typeName
	    * @param objs
	    * @return
	    * @throws Exception
	    */
			public static boolean insertBatch(JestClient jestClient,String indexName, String typeName, List<Object> objs) throws Exception {
	        Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexName).defaultType(typeName);  
	        for (Object obj : objs) {  
	            Index index = new Index.Builder(obj).build();  
	             bulk.addAction(index);  
	        }  
	        BulkResult br = jestClient.execute(bulk.build());  
	        return br.isSucceeded();  
	       }  
	      
	    /**
	     * 全文搜索
	     * @param indexName
	     * @param typeName
	     * @param query
	     * @return
	     * @throws Exception
	     */
	    public static String search(JestClient jestClient,String indexName, String typeName, String query) throws Exception {
	    	 Search search = new Search.Builder(query)
	    	 .addIndex(indexName)
	    	 .addType(typeName).setHeader(PWDKEY, getSecret())
	    	 .build();

	        JestResult jr = jestClient.execute(search);  
//	        System.out.println("--"+jr.getJsonString());
//	        System.out.println("--"+jr.getSourceAsObject(User.class));
	        return jr.getSourceAsString();  
	     }
	      
	   /**
	    * 删除索引
	    * @param indexName
	    * @return
	    * @throws Exception
	    */
	    public static boolean delete(JestClient jestClient,String indexName) throws Exception {
	        JestResult jr = jestClient.execute(new DeleteIndex.Builder(indexName).build());
	        return jr.isSucceeded();
	    }
	      
	   /**
	    * 删除数据
	    * @param indexName
	    * @param typeName
	    * @param id
	    * @return
	    * @throws Exception
	    */
	    public boolean delete(String indexName, String typeName, String id) throws Exception {
//	        DocumentResult dr = jestClient.execute(new Delete.Builder(id).index(indexName).type(typeName).build());
//	        return dr.isSucceeded();
			return false;
	    }

		//设置index的mapping（设置数据类型和分词方式）
		public void createIndexMapping(String index, String type, String mappingString) {
			//mappingString为拼接好的json格式的mapping串
			PutMapping.Builder builder = new PutMapping.Builder(index, type, mappingString);
			try {
				JestResult jestResult = jestClient.execute(builder.build());
				System.out.println("createIndexMapping result:{}" + jestResult.isSucceeded());
				if (!jestResult.isSucceeded()) {
					System.err.println("settingIndexMapping error:{}" + jestResult.getErrorMessage());
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		//获取index的mapping
		public String getMapping(String indexName, String typeName) {
			GetMapping.Builder builder = new GetMapping.Builder();
			builder.addIndex(indexName).addType(typeName);
			try {
				JestResult result = jestClient.execute(builder.build());
				if (result != null && result.isSucceeded()) {
					return result.getSourceAsObject(JsonObject.class).toString();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		}

		//获取索引index设置setting
		public boolean getIndexSettings(String index) {
			try {
				JestResult jestResult = jestClient.execute(new GetSettings.Builder().addIndex(index).build());
				System.out.println(jestResult.getJsonString());
				if (jestResult != null) {
					return jestResult.isSucceeded();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			return false;
		}

		//更改索引index设置setting
		public boolean updateIndexSettings(String index) {
			String source;
			XContentBuilder mapBuilder = null;
			try {
				mapBuilder = XContentFactory.jsonBuilder();
				mapBuilder.startObject().startObject("index").field("max_result_window", "1000000").endObject().endObject();
				source = mapBuilder.string();
				JestResult jestResult = jestClient.execute(new UpdateSettings.Builder(source).build());
				System.out.println(jestResult.getJsonString());
				if (jestResult != null) {
					return jestResult.isSucceeded();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			return false;
		}
		//获取索引 别名
		public static boolean getIndexAliases(String index) {
			try {
				JestResult jestResult = jestClient.execute(new GetAliases.Builder().addIndex(index).build());
				System.out.println(jestResult.getJsonString());
				if (jestResult != null) {
					return jestResult.isSucceeded();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			return false;
		}
		//添加索引别名
		public void addAlias(List<String> index, String alias) {
			try {
				AddAliasMapping build = new AddAliasMapping.Builder(index, alias).build();
				JestResult jestResult = jestClient.execute(new ModifyAliases.Builder(build).build());
				System.out.println("result:" + jestResult.getJsonString());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//获取索引模版
		public void getTemplate(String template) {
			try {
				JestResult jestResult = jestClient.execute(new GetTemplate.Builder(template).build());
				System.out.println("result:" + jestResult.getJsonString());
			} catch (IOException e) {
				e.printStackTrace();
			}

		}
		//添加索引模版
		public void putreturnreportTemplate() {
			String source;
			XContentBuilder mapBuilder = null;
			try {
				mapBuilder = XContentFactory.jsonBuilder();
				mapBuilder.startObject().field("template", "df_returnreport*").field("order", 1)//
						.startObject("settings").field("number_of_shards", 5)//五个分片
						.startObject("index").field("max_result_window", "1000000")//一次查询最大一百万
						.endObject()//
						.endObject()//
						.startObject("mappings")//
						.startObject("df_returnreport")//type名
						.startObject("properties")//
						.startObject("id").field("type", "long").endObject()//
						.startObject("username").field("type", "keyword").endObject()//
						.startObject("content").field("type", "text").field("analyzer", "ik_max_word").endObject()//
						.startObject("returntime").field("type", "date").field("format", "yyyy-MM-dd HH:mm:ss").endObject()//
						.startObject("gateway").field("type", "integer").endObject()//
						.endObject()//
						.endObject()//
						.endObject()//
						.startObject("aliases").startObject("df_returnreport").endObject().endObject()//别名
						.endObject();//
				source = mapBuilder.string();
				JestResult jestResult = jestClient.execute(new PutTemplate.Builder("my_returnreport", source).build());
				System.out.println("result:" + jestResult.getJsonString());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//索引优化
		public void optimizeIndex() {
			Optimize optimize = new Optimize.Builder().build();
			jestClient.executeAsync(optimize, new JestResultHandler<JestResult>() {
				public void completed(JestResult jestResult) {
					System.out.println("optimizeIndex result:{}" + jestResult.isSucceeded());
				}
				public void failed(Exception e) {
					e.printStackTrace();
				}
			});
		}
		//清理缓存
		public void clearCache() {
			try {
				ClearCache clearCache = new ClearCache.Builder().build();
				jestClient.execute(clearCache);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		/**
		 * 插入或更新文档
		 * @param indexId
		 * @param indexObject
		 * @param indexName
		 * @param indexType
		 * @return
		 */
		public static boolean insertOrUpdateDoc(String indexId, Object indexObject, String indexName, String indexType) {
			Index.Builder builder = new Index.Builder(indexObject);
			builder.setHeader(PWDKEY, getSecret());
			builder.id(indexId);
			builder.refresh(true);
			Index index = builder.index(indexName).type(indexType).build();
			try {
				JestResult result = jestClient.execute(index);
				if (result != null && !result.isSucceeded()) {
					throw new RuntimeException(result.getErrorMessage()+"插入更新索引失败!");
				}
			} catch (Exception e) {
				e.getStackTrace();
				return false;
			}
			return true;
		}

		protected static String getSecret() {
			long time = System.currentTimeMillis() / 1000;
			return time + "," + DigestUtils.md5Hex(String.valueOf(time)).toUpperCase();
		}

    /**
     * 带条件检索
     * 实现类似  select * from table where filed = queryString AND (... or条件字段 ...)
     * @param indexName   索引名
     * @param typeName    类型名
     * @param queryString 查询内容
     * @param field       字段对象，包括查询字段及查询字段的值
     * @param fieldForOrs 查询条件 or区分
     * @param client
     * @param pageNumber  页码
     * @param pageSize    页数
     * @return
     */
    public JestResult index(String indexName, String typeName, String queryString, String field, List<Field> fieldForOrs, JestClient client, int pageNumber, int pageSize) {
        //声明一个SearchSourceBuilder对象，构造检索请求体
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //构造查询哪个字段
        if(StringUtils.isEmpty(field)) {
            //没有检索条件，则全字段查询
            boolQueryBuilder = boolQueryBuilder.must(QueryBuilders.queryStringQuery(queryString));
        } else {
            boolQueryBuilder = boolQueryBuilder.must(QueryBuilders.matchQuery(field,queryString));
        }

        BoolQueryBuilder innerQueryBuilder = QueryBuilders.boolQuery();
        for(Field fieldValue : fieldForOrs) {
//            innerQueryBuilder = innerQueryBuilder.should(QueryBuilders.termQuery(fieldValue.getName(),fieldValue.getFieldValue()));
        }
        boolQueryBuilder = boolQueryBuilder.filter(innerQueryBuilder);

        searchSourceBuilder.query(boolQueryBuilder);

        //设置高亮字段
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field(field);
        highlightBuilder.preTags("<em>").postTags("</em>");
        highlightBuilder.fragmentSize(200);
        searchSourceBuilder.highlight(highlightBuilder);

        //设置分页
        searchSourceBuilder.from((pageNumber - 1) * pageSize);
        searchSourceBuilder.size(pageSize);

        //构建Search对象
        Search search =  new Search.Builder(searchSourceBuilder.toString())
                .addIndex(indexName)
                .addType(typeName)
                .build();

        SearchResult searchResult = null;
        try {
            searchResult = client.execute(search);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return searchResult;
    }
}
